iT邦幫忙

2021 iThome 鐵人賽

DAY 21
0

前面說那麼多次以後會遇到大型專案會怎樣怎樣的,所以現在就要來說一下大型專案長怎樣,如何將大型專案拆解開來看,讓你不會拿到一大包東西完全不知如何下手。

話說因為 Flask 本身就是小框架,也沒太多重要的或常用的東西可以講;再加上我是想把 Flask 本體講完再講其他的啦,所以這篇算是有關 Flask 本體的最後一篇了。下一篇就會進入到 Flask 插件的部分(是說上一篇其實就有講到插件了)。

Blueprint

如果網站架構持續運作了好幾年,中間不斷地修修改改,功能越來越多,架構越來龐大,將全部的路由都放在一個檔案裏面會造成維護上的困難,所以勢必要將不同功能的路由拆成不同檔案,以利維護。

而 Blueprints 是 Flask 提供的將不同功能的路由模組化管理的方式,不過路由是分開了,那前端視圖跟靜態文件呢?

如果不做設定,前端視圖跟靜態文件還是在 templatesstatic 裡面,這樣的優點是不同模組間能夠套用同樣的父視圖(base.html 那個東東);而如果想要不同模組間可以有不同的視圖,也能夠分開擺放(也可以一部份分開,一部分放一起)。

位置統一

那就直接來看如何使用吧。讓我們拿前面的架構再來改一下:

ithome
├── account  # 取個有意義的名字
│   └── api.py  # 隨便取個名字
├── static
│   └── logo.png
├── templates
│   ├── account  # 它改個有意義的名字
│   │   ├── home.html
│   │   ├── login.html
│   │   └── settings.html
│   ├── base.html
│   ├── index.html
│   └── page_not_found.html
├── app.py
├── configs.py
├── Pipfile
└── Pipfile.lock

然後將 app.py 裡面的 home, login, settings 搬進去 account -> api.py 裡面,再各加上幾行。

然後因為移動了 index.htmlpage_not_found.html,還有改了 res 的資料夾名稱,所以有關 render_template 的都需要改一下;以及路由需要修正一下。

app.py 裡面應該剩這樣:

from flask import Flask, render_template, make_response


# 這個 app 是 api.py 裡面的 app,建議改個有意義的名字,同樣都叫 app 是我懶得改
# 如果名稱衝突到,可以使用 as 來取個暱稱。
from account.api import app as account
from configs import config


app = Flask(__name__)
app.config.from_object(config.DevelopmentConfig)

# 註冊 blueprint
app.register_blueprint(account)

# 這邊的 app 是上面 Flask 的 app
@ app.route('/')
def index():
    return render_template('index.html')


''' 應該還有一些其他的東西,不過這裡沒有要用到,註解掉或刪掉都沒關係 '''


@ app.errorhandler(404)
def page_not_found(error):
    response = make_response(render_template(
        'page_not_found.html', error=error), 404)

    return response


if __name__ == "__main__":
    app.run()

前面的那三個路由搬到 api.py 裡面,有關 render_template 的記得改一下。

# 新增這行
from flask import Blueprint, redirect, request, render_template, make_response, url_for


# 還有新增這行,同樣叫 app 只是我懶得改,建議還是改有意義的名字。
app = Blueprint('account', __name__)


@app.route('/home', methods=['GET'])
def home():
    if 'username' in request.cookies:
        user = request.cookies.get('username')

    return render_template('account/home.html', username=user)


@app.route('/login', methods=['GET', 'POST'])
def login():
    if request.method == 'GET':
        response = make_response(render_template('account/login.html'))
    elif request.method == 'POST':  # 表單送出後會到這裡
        account = request.values.get('username', None)
        # 驗證是否有這個使用者以及密碼是否正確,生出驗證結果 auth_result
        auth_result = 'success'  # 假設成功
        ''' 建立回應 '''
        if auth_result == 'success':  # 如果都正確
            response = make_response(redirect(url_for('account.home')))

            response.set_cookie('username', account)  # 先使用 Cookie 就好
        else:  # 如果錯誤
            response = make_response(redirect(url_for('account.login')))
    else:
        response = make_response(redirect(url_for('index')))

    return response


@app.route('/settings', methods=['GET'])
def settings():
    if 'username' in request.cookies:
        user = request.cookies.get('username')

    return render_template('account/settings.html', username=user)

改到這裡就差不多了,如果在 .html 裡面有使用到 url_for 的要記得改一下。例如 url_for('login') 要改成 url_for('account.login') ,前面加 Blueprint 中的第一個參數還有英文句號就 OK 了(還有不是那個 Blueprint 下的路由前面不要亂給他加名稱,不要亂認親)。

如果要改的都有改到的話,這幾個功能應該跟移動之前是差不多的,不過這幾個功能就分開來了,在維護時也能更快、更輕鬆的維護。

位置分開

如果要將前端視圖與靜態文件分開,首先至少要將它們搬到相應的位置對吧。

ithome
├── account
│   ├── static_account
│   │   └── logo.png
│   ├── templates_account
│   │   ├── account  # 因為我不想改 render_template,所以就留著它了。
│   │   │   ├── home.html
│   │   │   ├── login.html
│   │   │   └── settings.html
│   │   └── base.html
│   └── api.py
├── static
│   └── logo.png
├── templates
│   ├── base.html
│   ├── index.html
│   └── page_not_found.html
├── app.py
├── configs.py
├── Pipfile
└── Pipfile.lock

搬完之後,再到 api.py 設定新的前端視圖與靜態文件位置,

api.py

from flask import Blueprint, redirect, request, render_template, make_response, url_for


app = Blueprint('account', __name__, static_folder='static_account',
                static_url_path='/img', template_folder='templates_account',
                url_prefix='/account')


@app.route('/home', methods=['GET'])
def home():
    if 'username' in request.cookies:
        user = request.cookies.get('username')

    return render_template('account/home.html', username=user)


@app.route('/login', methods=['GET', 'POST'])
def login():
    if request.method == 'GET':
        response = make_response(render_template('account/login.html'))
    elif request.method == 'POST':  # 表單送出後會到這裡
        account = request.values.get('username', None)
        # 驗證是否有這個使用者以及密碼是否正確,生出驗證結果 auth_result
        auth_result = 'success'  # 假設成功
        ''' 建立回應 '''
        if auth_result == 'success':  # 如果都正確
            response = make_response(redirect(url_for('account.home')))

            response.set_cookie('username', account)  # 先使用 Cookie 就好
        else:  # 如果錯誤
            response = make_response(redirect(url_for('account.login')))
    else:
        response = make_response(redirect(url_for('index')))

    return response


@app.route('/settings', methods=['GET'])
def settings():
    if 'username' in request.cookies:
        user = request.cookies.get('username')

    return render_template('account/settings.html', username=user)

Blueprint 一樣有著 static_folderstatic_url_pathtemplate_folder ,用法也跟 Day 17 一樣。而 url_prefix 是什麼呢?

先來看看不加 url_prefix 會發生什麼事。

再來看看加了 url_prefix 會發生什麼事。

有注意到 url 的變化嗎?就是在這個 Blueprint 裡面的路由都加上 url 前綴。

那麼就大概這樣,有關 Flask 本體大概就這樣就結束了,下一篇開始就是 Flask 的插件了。

大家掰~掰~


上一篇
Day 20 Flask Session
下一篇
Day 22 Flask-SocketIO
系列文
月光下的Flask之旅30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言